#include "../../rdx/src/rdx/rdx_pragmas.hpp"
#include "../../rdx/src/rdx/rdx_objectloader.hpp"
#include "../tdp2/tdp2_vfs.hpp"

#include <stdlib.h>
#include <stdio.h>

#include "rdxsupport.hpp"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>


using namespace RDX;
using namespace RDX::ObjectManagement;
using namespace RDX::Programmability;
using namespace RDX::Marshaling;
using namespace RDX::Utility;


static void *myAlloc (void *opaque, void *ptr, LargeInt sz, LargeInt align)
{
	return _aligned_realloc(ptr, sz, align);
}

static void *myAllocExecutable(void *opaque, LargeInt sz)
{
	void* p = VirtualAllocEx(GetCurrentProcess(), NULL, static_cast<SIZE_T>(sz), MEM_COMMIT, PAGE_READWRITE);
	return p;
}

static void myCommitExecutable(void *opaque, void *ptr, LargeInt sz)
{
	DWORD prevProtect;
	VirtualProtectEx(GetCurrentProcess(), ptr, static_cast<SIZE_T>(sz), PAGE_EXECUTE_READ, &prevProtect);
}

static void myFreeExecutable(void *opaque, void *ptr, LargeInt sz)
{
	VirtualFreeEx(GetCurrentProcess(), ptr, static_cast<SIZE_T>(sz), MEM_RELEASE);
}

namespace RDX
{
	namespace ObjectManagement
	{
		void DeserializePackage(OperationContext *ctx, IObjectManager *objManager, RDX::IO::IFileStream *stream);
	}
}

namespace RDXSupport
{
	TDP::OS::OSFileSystem osfs(NULL, RDX_STATIC_STRING("rdxclasses"));

	enum
	{
		DOMAIN_C2Test = DOMAIN_Custom,
	};

	int MyPrintLine(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread,
		RuntimeStackValue *prv)
	{
		struct myParameters
		{
			Value<String*> str;
		};

		myParameters *params = ParametersFromPRV<myParameters>(prv);
		wprintf(L"%s\n", params->str.GetValue()->AsChars());

		return RuntimeState::Active;
	}

	void GetRDXSupportPackage(SimpleRDXSupportPackage *pkg)
	{
		pkg->alloc.reallocFunc = myAlloc;
		pkg->fs = &osfs;
	}
	
	void LoadZonePolicy(RDX::OperationContext *ctx,
		RDX::ObjectManagement::IObjectManager *objm, RDX::Security::ZonePolicyPackageHost *host, const Char *path)
	{
		RDX_TRY(ctx)
		{
			RuntimeObjectLoaderHost zoneLoaderHost(host, DOMAIN_Runtime, &osfs);
			zoneLoaderHost.SetPackage(path, true);

			CRef<Security::Zone*> zones;
					
			RDX_PROTECT_ASSIGN(ctx, zones, objm->LoadObject(ctx, &zoneLoaderHost).Cast<Security::Zone*>());
			RDX_PROTECT(ctx, host->LoadZones(ctx, zones));
		}
		RDX_CATCH(ctx)
		{
			RDX_RETHROW(ctx);
		}
		RDX_ENDTRY
	}
}
